// Copyright (C) 1953-2021 NUDT
// Verilog module name - packet_digest_extract.v
// Version: V4.0.20220524
// Created:
//         by - fenglin 
////////////////////////////////////////////////////////////////////////////
// Description:
//         extract keyword of packet.
///////////////////////////////////////////////////////////////////////////

`timescale 1ns/1ps

module packet_digest_extract#(parameter inport = 6'b000000)
(
        i_clk,
        i_rst_n,
       
        iv_data,
        i_data_wr, 
		iv_eth_type,	
        iv_pkt_priority,
        
        i_pkt_bufid_wr,
        iv_pkt_bufid  ,        
 
        iv_free_bufid_fifo_rdusedw  ,   
        iv_rc_police_threshold ,         
        iv_hpriority_be_police_threshold,
        iv_lpriority_be_police_threshold ,
        
        o_md_wr ,
        ov_md   ,
        o_pkt_bufid_wr,
        ov_pkt_bufid ,
       
        ov_data,
        o_data_wr,
        ov_pkt_discard_cnt
);  
// clk & rst  
input                i_clk	;
input                i_rst_n;
//pkt input
input       [8:0]   iv_data;
input               i_data_wr;
input               i_pkt_bufid_wr;
input       [8:0]   iv_pkt_bufid  ; 

input       [15:0]  iv_eth_type;
input       [2:0]   iv_pkt_priority;

input       [8:0]   iv_free_bufid_fifo_rdusedw;
input       [8:0]   iv_hpriority_be_police_threshold;
input       [8:0]   iv_rc_police_threshold;
input       [8:0]   iv_lpriority_be_police_threshold;

output reg  [299:0] ov_md;
output reg          o_md_wr;

output  reg         o_pkt_bufid_wr;
output  reg [8:0]   ov_pkt_bufid  ;

output reg  [8:0]   ov_data;
output reg          o_data_wr;
output reg  [15:0]  ov_pkt_discard_cnt;
//***************************************************
//          extract keyword from pkt 
//***************************************************

reg 		[7:0]		ip_type;
reg         [3:0]       pde_state;
reg         [11:0]      byte_cnt;
reg 		[6:0]		rv_iphead_length; 
reg                     r_replication_flag;
localparam  IDLE_S              = 4'd0,
            EXTRACT_TSNMD_S     = 4'd1,
            MAPPED_THIRD_S      = 4'd2,
            MAPPED_FOURTH_S     = 4'd3,
            MAPPED_FIFTH_S      = 4'd4,
            MAPPED_SIXTH_S      = 4'd5,
			MAPPED_SEVENTH_S    = 4'd6,
			MAPPED_EIGHTH_S     = 4'd7,
            MAPPED_OTHER_S      = 4'd8,
            TRAN_STANDARD_S     = 4'd9,
            DISC_S              = 4'd10;
always@(posedge i_clk or negedge i_rst_n)
    if(!i_rst_n) begin
        ov_data             <= 9'b0;
        o_data_wr           <= 1'b0;
        ov_pkt_bufid        <= 9'b0;
        o_pkt_bufid_wr      <= 1'b0;
        o_md_wr             <= 1'b0;
        ov_md               <= 300'b0;
        byte_cnt            <= 12'd0;
        ov_pkt_discard_cnt  <= 16'b0;
        r_replication_flag  <= 1'b0;
		ip_type				<= 8'd0;
        rv_iphead_length    <= 7'b0;
        pde_state           <= IDLE_S;
    end
    else begin
        case(pde_state)
            IDLE_S:begin
                if((i_data_wr == 1'b1) && (iv_data[8] == 1'b1))begin//head
                    ov_data       <= iv_data;
                    ov_pkt_bufid  <= iv_pkt_bufid;
                    ov_md[47:0]   <= {ov_md[39:0],iv_data[7:0]};
                    ov_md[114:96] <= {iv_pkt_priority,iv_eth_type};
                    o_md_wr  <= 1'b0;
					if(iv_eth_type == 16'hff01)begin//tsmp pkt
                        if((iv_free_bufid_fifo_rdusedw <=  iv_hpriority_be_police_threshold) || (iv_free_bufid_fifo_rdusedw <=  iv_rc_police_threshold))begin //discard pkt when bufid under threshold or bufid is used up
                            o_data_wr           <= 1'h0;
                            o_pkt_bufid_wr      <= 1'b0;
                            ov_pkt_discard_cnt  <= ov_pkt_discard_cnt + 1'b1;
                            pde_state           <= DISC_S;
                        end 
                        else begin
                            o_data_wr           <= 1'h1;
                            o_pkt_bufid_wr      <= i_pkt_bufid_wr;
                            byte_cnt            <= 12'b1;
                            pde_state           <= TRAN_STANDARD_S;
                        end
                    end
                    else if(iv_eth_type == 16'h8100)begin//tsn pkt
                        if((iv_pkt_priority==3'd3)||(iv_pkt_priority==3'd4))begin
                            if(iv_free_bufid_fifo_rdusedw <=  iv_rc_police_threshold)begin//discard pkt when bufid under threshold or bufid is used up
                                o_data_wr         <= 1'h0;
                                o_pkt_bufid_wr    <= 1'b0;
                                ov_pkt_discard_cnt<= ov_pkt_discard_cnt + 1'b1;
                                pde_state         <= DISC_S;
                            end 
                            else begin
                                o_data_wr         <= 1'h1;
                                byte_cnt          <= 12'b1;
                                o_pkt_bufid_wr    <= i_pkt_bufid_wr;
                                pde_state         <= EXTRACT_TSNMD_S;
                            end                       
                        end
                        else if((iv_pkt_priority==3'd5)||(iv_pkt_priority==3'd6)||(iv_pkt_priority==3'd7))begin
                            if(iv_free_bufid_fifo_rdusedw == 9'h0) begin//discard pkt when bufid under threshold or bufid is used up
                                o_data_wr         <= 1'h0;
                                o_pkt_bufid_wr    <= 1'b0;
                                ov_pkt_discard_cnt<= ov_pkt_discard_cnt + 1'b1;
                                pde_state         <= DISC_S;
                            end 
                            else begin
                                o_data_wr         <= 1'h1;
                                byte_cnt          <= 12'b1;
                                o_pkt_bufid_wr    <= i_pkt_bufid_wr;
                                pde_state         <= EXTRACT_TSNMD_S;
                            end                       
                        end                        
                        else begin
                            if((iv_free_bufid_fifo_rdusedw <=  iv_lpriority_be_police_threshold) || (iv_free_bufid_fifo_rdusedw <=  iv_hpriority_be_police_threshold) || (iv_free_bufid_fifo_rdusedw <=  iv_rc_police_threshold)) begin//discard pkt when bufid under threshold or bufid is used up
                                o_data_wr          <= 1'h0;
                                o_pkt_bufid_wr     <= 1'b0;
                                ov_pkt_discard_cnt <= ov_pkt_discard_cnt + 1'b1;
                                pde_state          <= DISC_S;
                            end 
                            else begin
                                o_data_wr          <= 1'h1;
                                byte_cnt           <= 12'b1;
                                o_pkt_bufid_wr     <= i_pkt_bufid_wr;
                                pde_state          <= EXTRACT_TSNMD_S;
                            end
                        end
					end
					else begin
						if(iv_pkt_priority==3'd1)begin
                            if((iv_free_bufid_fifo_rdusedw <=  iv_hpriority_be_police_threshold) || (iv_free_bufid_fifo_rdusedw <=  iv_rc_police_threshold)) begin//discard pkt when bufid under threshold or bufid is used up
                                o_data_wr          <= 1'h0;
                                o_pkt_bufid_wr     <= 1'b0;
                                ov_pkt_discard_cnt <= ov_pkt_discard_cnt + 1'b1;
                                pde_state          <= DISC_S;
                            end 
                            else begin
                                o_data_wr          <= 1'h1;
                                byte_cnt           <= 12'b1;
                                o_pkt_bufid_wr     <= i_pkt_bufid_wr;
                                pde_state          <= TRAN_STANDARD_S;
                            end	
						end	
						else begin
                            if((iv_free_bufid_fifo_rdusedw <=  iv_lpriority_be_police_threshold) || (iv_free_bufid_fifo_rdusedw <=  iv_hpriority_be_police_threshold) || (iv_free_bufid_fifo_rdusedw <=  iv_rc_police_threshold)) begin//discard pkt when bufid under threshold or bufid is used up
                                o_data_wr          <= 1'h0;
                                o_pkt_bufid_wr     <= 1'b0;
                                ov_pkt_discard_cnt <= ov_pkt_discard_cnt + 1'b1;
                                pde_state          <= DISC_S;
                            end 
                            else begin
                                o_data_wr          <= 1'h1;
                                byte_cnt           <= 12'b1;
                                o_pkt_bufid_wr     <= i_pkt_bufid_wr;
                                pde_state          <= TRAN_STANDARD_S;
                            end							
						end
					end
				end
				else begin
					ov_md         <= 300'b0;
                    o_md_wr       <= 1'b0;
                    byte_cnt      <= 12'b0;
                    o_pkt_bufid_wr<= 1'b0;
                    ov_pkt_bufid  <= 9'b0;
					ov_data       <= 9'b0;
					o_data_wr     <= 1'b0;
					pde_state     <= IDLE_S;
				end
			end
            TRAN_STANDARD_S:begin           //standard ethernet type
                ov_data         <= iv_data;
                o_data_wr       <= i_data_wr;
                byte_cnt        <= byte_cnt + 1'b1;               
                if(i_data_wr == 1'b1 && iv_data[8] ==  1'b1)begin//tail
                    pde_state   <= IDLE_S;
                end
                else if(i_data_wr == 1'b1 && iv_data[8] ==  1'b0)begin//middle
                    pde_state   <= TRAN_STANDARD_S;
                end
                else begin//invalid
                    pde_state   <= IDLE_S;
                end
                //send descriptor
                if(byte_cnt < 12'd6) begin //DMAC
				    ov_md[47:0]  <= {ov_md[39:0],iv_data[7:0]};				
                    o_md_wr      <= 1'b0;
					o_pkt_bufid_wr      <= i_pkt_bufid_wr;
                    ov_pkt_bufid        <= iv_pkt_bufid;					
                end
                else if((byte_cnt >12'd5)&&(byte_cnt < 12'd12))begin  //SMAC
				    ov_md[95:48] <= {ov_md[87:48],iv_data[7:0]};
                    o_md_wr      <= 1'b0;
					o_pkt_bufid_wr      <= i_pkt_bufid_wr;
                    ov_pkt_bufid        <= iv_pkt_bufid;					
                end 
                else if(byte_cnt==12'd14)begin      
				    if(ov_md[111:96]==16'h0800)begin
                        rv_iphead_length  <= {3'b0,iv_data[3:0]} << 2;
                    end
                    else begin
                        rv_iphead_length <= 7'd20;
                    end
                    o_md_wr           <= 1'b0;
					o_pkt_bufid_wr<= 1'b0;
                    ov_pkt_bufid  <= 9'b0;
                end  
                else if(byte_cnt==12'd16)begin      
				    ov_md[139:137] <=iv_data[2:0];
                    o_md_wr        <= 1'b0;
					o_pkt_bufid_wr<= 1'b0;
                    ov_pkt_bufid  <= 9'b0;
                end   
                else if(byte_cnt==12'd17)begin     //ip length
				    ov_md[136:129] <=iv_data[7:0];
                    o_md_wr        <= 1'b0;
					o_pkt_bufid_wr<= 1'b0;
                    ov_pkt_bufid  <= 9'b0;
                end   
				else if(byte_cnt==12'd23)begin     //ip type
				    ip_type <= iv_data[7:0];
                end 
				
                else if(byte_cnt == 12'd24)begin                           //inport
				    ov_md[154:149] <= inport;
                    o_md_wr        <= 1'b0;
				    o_pkt_bufid_wr<= 1'b0;
                    ov_pkt_bufid  <= 9'b0;
                    if(ov_md[111:96]==16'h0800)begin
                        ov_md[139:129] <= ov_md[139:129] +11'd14;
                    end
                    else begin 
                        ov_md[139:129]<=11'h0;
                    end
                end
				
				else if((byte_cnt >12'd29)&&(byte_cnt < 12'd34))begin  //DIP
	
					o_md_wr        <= 1'b0;
				    o_pkt_bufid_wr<= 1'b0;
                    ov_pkt_bufid  <= 9'b0;
					if (ov_md[111:96]==16'h0800)begin 
					    ov_md[298:267] <= {ov_md[290:267],iv_data[7:0]};
					end
					else begin 
					    ov_md [298:267]   <= {ov_md[290:267],8'b0};
					end
				end	
				//else if(byte_cnt == 12'd34)begin  //IGMP type
                else if(byte_cnt == {5'b0,rv_iphead_length} + 12'd14)begin  //IGMP type
					o_md_wr        <= 1'b1;
				    o_pkt_bufid_wr<= 1'b0;
                    ov_pkt_bufid  <= 9'b0;
					if((ov_md[111:96]==16'h0800)&&(ip_type == 8'h02))begin 

						if (iv_data[7:0]==8'h11)begin 
							ov_md[266:264] <= 3'b001;
						end
						else if ((iv_data[7:0]==8'h12)||(iv_data[7:0]==8'h16)||(iv_data[7:0]==8'h22))begin 
							ov_md[266:264] <= 3'b010;
						end
						else if (iv_data[7:0]==8'h17)begin 
							ov_md[266:264] <= 3'b011;
						end
						else begin 
							ov_md[266:264] <= 3'b000;
						end
					end
					else begin
                         ov_md[266:264] <= 3'b000;                 
					end
				end
                else begin
                    ov_md        <= ov_md;                   
                    o_md_wr      <= 1'b0;
                    o_pkt_bufid_wr<= 1'b0;
                    ov_pkt_bufid  <= 9'b0;
					ip_type 	<= ip_type;
                end
            end
            EXTRACT_TSNMD_S:begin          //mapped ethernet type
                ov_data         <= iv_data;
                o_data_wr       <= i_data_wr;
                byte_cnt        <= byte_cnt + 1'b1;               
                if(i_data_wr == 1'b1 && iv_data[8] ==  1'b1)begin//tail
                    pde_state    <= IDLE_S;
                end
                else if(i_data_wr == 1'b1 && iv_data[8] ==  1'b0)begin//middle
                    pde_state    <= EXTRACT_TSNMD_S;
                end
                else begin//invalid
                    pde_state    <= IDLE_S;
                end
                //send descriptor
                if(byte_cnt < 12'd6) begin //DMAC
				    ov_md[47:0]  <= {ov_md[39:0],iv_data[7:0]};				
                    o_md_wr      <= 1'b0;
					o_pkt_bufid_wr <= i_pkt_bufid_wr;
                    ov_pkt_bufid   <= iv_pkt_bufid;
                end
                else if((byte_cnt >12'd5)&&(byte_cnt < 12'd12))begin      //SMAC
				    ov_md[95:48] <= {ov_md[87:48],iv_data[7:0]};
                    o_md_wr      <= 1'b0;
					o_pkt_bufid_wr<= i_pkt_bufid_wr;
                    ov_pkt_bufid  <= iv_pkt_bufid;
                end  
                else if(byte_cnt==12'd14)begin                         
                    r_replication_flag  <= iv_data[7];
                    ov_md[128:123]      <=iv_data[5:0];
                    o_md_wr             <= 1'b0;
					o_pkt_bufid_wr      <= i_pkt_bufid_wr;
                    ov_pkt_bufid        <= iv_pkt_bufid;
                end   
                else if(byte_cnt==12'd15)begin     
                    ov_md[122:115] <=iv_data[7:0];   //flowid
                    o_md_wr        <= 1'b0;
					o_pkt_bufid_wr <= i_pkt_bufid_wr;
                    ov_pkt_bufid   <= iv_pkt_bufid;
                end
                else if(byte_cnt > 12'd15)begin
                    if(r_replication_flag)begin//replication frame;there is r-tag.                    
                        if(byte_cnt==12'd26)begin      
                            ov_md[139:137] <=iv_data[2:0];
                            o_md_wr        <= 1'b0;
                        end   
                        else if(byte_cnt==12'd27)begin     //ip length
                            ov_md[136:129] <=iv_data[7:0];
                            o_md_wr        <= 1'b0;
                        end   				
                        else if(byte_cnt==12'd28)begin    
                            ov_md[154:149] <= inport;
                            o_md_wr        <= 1'b1;
                            ov_md[139:129] <= ov_md[139:129] +11'd14;
                            o_pkt_bufid_wr<= 1'b0;
                            ov_pkt_bufid  <= 9'b0;
                        end                     
                        else begin
                            ov_md          <= ov_md;                   
                            o_md_wr        <= 1'b0;
                            o_pkt_bufid_wr<= 1'b0;
                            ov_pkt_bufid  <= 9'b0;                    
                        end
                    end
                    else begin//not replication frame;there isn't r-tag. 
                        if(byte_cnt==12'd20)begin      
                            ov_md[139:137] <=iv_data[2:0];
                            o_md_wr        <= 1'b0;
                        end   
                        else if(byte_cnt==12'd21)begin     //ip length
                            ov_md[136:129] <=iv_data[7:0];
                            o_md_wr        <= 1'b0;
                        end   				
                        else if(byte_cnt==12'd22)begin    
                            ov_md[154:149] <= inport;
                            o_md_wr        <= 1'b1;
                            ov_md[139:129] <= ov_md[139:129] +11'd14;
                            o_pkt_bufid_wr<= 1'b0;
                            ov_pkt_bufid  <= 9'b0;
                        end                     
                        else begin
                            ov_md          <= ov_md;                   
                            o_md_wr        <= 1'b0;
                            o_pkt_bufid_wr<= 1'b0;
                            ov_pkt_bufid  <= 9'b0;                    
                        end                    
                    end
                end
                else begin
                    ov_md          <= ov_md;                   
                    o_md_wr        <= 1'b0;
                    o_pkt_bufid_wr<= 1'b0;
                    ov_pkt_bufid  <= 9'b0;                    
                end                
            end
  
            DISC_S:begin
                ov_data          <= 9'h0;
                o_data_wr        <= 1'h0;
                o_pkt_bufid_wr   <= 1'b0;
                ov_pkt_bufid     <= 9'b0;
                ov_md            <= 300'b0;
                o_md_wr          <= 1'b0;
				ip_type 		 <= 8'b0;
                if(i_data_wr == 1'b1 && iv_data[8] == 1'b1)begin
                    pde_state    <= IDLE_S;
                end
                else begin
                    pde_state    <= DISC_S;
                end
            end

            default:begin
                ov_data          <= 9'b0;
                o_data_wr        <= 1'b0;
                o_pkt_bufid_wr   <= 1'b0;
                ov_pkt_bufid     <= 9'b0;
                o_md_wr          <= 1'b0;
                ov_md            <= 300'b0;
                byte_cnt         <= 12'b0;
				ip_type 		 <= 8'b0;
                pde_state        <= IDLE_S;
            end
        endcase
    end
endmodule
